#include "drv_sht30.h"
#include "bsp.h"
#include "bsp_i2c1.h"

/* SHT30 温湿度计 */



/* 命令(寄存器) */

//软件复位
#define SHT30_CMD_SOFT_RESET    0x30A2

//周期测量模式
#define SHT30_CMD_HIGH_ENABLED 0x2C06
#define SHT30_CMD_MEDIUM_ENABLED 0x2C0D
#define SHT30_CMD_LOW_ENABLED 0x2C10
#define SHT30_CMD_HIGH_DISABLED 0x2400
#define SHT30_CMD_MEDIUM_DISABLED 0x240B
#define SHT30_CMD_LOW_DISABLED 0x2416

//周期测量模式, CMD_MPS
#define SHT30_CMD_HIGH_0_5 0x2032
#define SHT30_CMD_MEDIUM_0_5 0x2024
#define SHT30_CMD_LOW_0_5 0x202F
#define SHT30_CMD_HIGH_1 0x2130
#define SHT30_CMD_MEDIUM_1 0x2126
#define SHT30_CMD_LOW_1 0x212D
#define SHT30_CMD_HIGH_2_ 0x2236
#define SHT30_CMD_MEDIUM_2 0x2220
#define SHT30_CMD_LOW_2 0x222B
#define SHT30_CMD_HIGH_4 0x2334
#define SHT30_CMD_MEDIUM_4 0x2322
#define SHT30_CMD_LOW_4 0x2329
#define SHT30_CMD_HIGH_10 0x2737
#define SHT30_CMD_MEDIUM_10 0x2721
#define SHT30_CMD_LOW_10 0x272A

//周期测量模式读取数据命令
#define SHT30_CMD_READOUT_FOR_PERIODIC_MODE 0xE000



// #define SHT30_IIC_ADDR  (0x44 << 1)
#define SHT30_IIC_ADDR  0x88

/* static var */


/* static func */

#define drv_sht30_iic_start         bsp_i2c1_start
#define drv_sht30_iic_stop          bsp_i2c1_stop
#define drv_sht30_iic_ack           bsp_i2c1_ack
#define drv_sht30_iic_noack         bsp_i2c1_noack
#define drv_sht30_iic_wait_ack      bsp_i2c1_wait_ack
#define drv_sht30_iic_write_byte    bsp_i2c1_write_byte
#define drv_sht30_iic_read_byte     bsp_i2c1_read_byte_ack


static uint8_t sht30_crc8(uint8_t* const message, uint8_t initial_value)
{
    #define CRC8_POLYNOMIAL 0x31
    uint8_t  ret;        //余数
    uint8_t  i = 0, j = 0;  //循环变量

    /* 初始化 */
    ret = initial_value;
    for(j = 0; j < 2;j++)
    {
        ret ^= message[j];

        /* 从最高位开始依次计算  */
        for (i = 0; i < 8; i++)
        {
            if (ret & 0x80)
            {
                ret = (ret << 1)^CRC8_POLYNOMIAL;
            }
            else
            {
                ret = (ret << 1);
            }
        }
    }

    return ret;
}

//发送命令(只发送,无数据接收)
static void drv_sht30_send_cmd(uint16_t cmd)
{
    bsp_i2c1_lock();

    drv_sht30_iic_start();

    /* addr */
    drv_sht30_iic_write_byte(SHT30_IIC_ADDR);
    drv_sht30_iic_wait_ack();

    /* cmd-2bytes */
    drv_sht30_iic_write_byte((uint8_t)(cmd >> 8));
    drv_sht30_iic_wait_ack();
    drv_sht30_iic_write_byte((uint8_t)(cmd & 0x00FF));
    drv_sht30_iic_wait_ack();

    drv_sht30_iic_stop();

    bsp_i2c1_unlock();
}

//读取数据,返回数据格式为 data_MSB+data_LSB+data_crc, 数量为3的倍数
static uint8_t drv_sht30_read_reg(uint16_t cmd, uint8_t *pbuf, uint8_t size)
{
    uint8_t tmp;
    uint8_t i;
    uint8_t ret;

    if (size % 3) return 1; //buf必须为3的倍数

    bsp_i2c1_lock();

	drv_sht30_iic_start();

	/* addr */
	drv_sht30_iic_write_byte(SHT30_IIC_ADDR);
	drv_sht30_iic_wait_ack();
	
	/* cmd-2bytes */
    drv_sht30_iic_write_byte((uint8_t)(cmd >> 8));
    drv_sht30_iic_wait_ack();
    drv_sht30_iic_write_byte((uint8_t)(cmd & 0x00FF));
    drv_sht30_iic_wait_ack(); 

	/* data */
	drv_sht30_iic_start();
	drv_sht30_iic_write_byte(SHT30_IIC_ADDR | 0x01);
	drv_sht30_iic_wait_ack();

    for (i=0; i<size; i++)
    {
        pbuf[i] = drv_sht30_iic_read_byte();
    }
	drv_sht30_iic_noack();

	drv_sht30_iic_stop();

    bsp_i2c1_unlock();

    /* crc */
    ret = 0;
    for (i=0; i<size; i+=3)
    {
        tmp = sht30_crc8(&pbuf[i], 0xFF);
        // printf("crc: [0x%02X:0x%02X]\r\n", tmp, pbuf[i + 2]);
        if (tmp != pbuf[i + 2])
        {
            ret |= 1;
            printf("crc [0x%02X:0x%02X]\r\n", tmp, pbuf[i + 2]);
        }
        // i += 3;
    }

    return ret;
}


/* export func */

/**
 * @brief 初始化
 *
 */
void drv_sht30_init(void)
{
    bsp_i2c1_init();

    drv_sht30_reset();

    drv_sht30_send_cmd(SHT30_CMD_MEDIUM_2);     //周期测量模式
}

/**
 * @brief 软复位
 * 
 */
void drv_sht30_reset(void)
{
    drv_sht30_send_cmd(SHT30_CMD_SOFT_RESET);
    delay_ms(20);
}

/**
 * @brief 获取状态
 * 
 * @param sta 
 * @return uint8_t 
 */
uint8_t drv_sht30_get_status(uint16_t *sta)
{
    uint8_t buff[3];

    drv_sht30_read_reg(SHT30_CMD_READOUT_FOR_PERIODIC_MODE, buff, 3);

    *sta = ((uint16_t)buff[0]<<8) | buff[1];

    return 0;
}

/**
 * @brief 读取温湿度
 * 
 * @param temperature 温度('C)
 * @param humidity 湿度(%)
 * @return uint8_t 
 */
uint8_t drv_sht30_get_temp_hum(float *temperature, float *humidity)
{
	uint16_t tmp;
    uint8_t buff[6];

    drv_sht30_read_reg(SHT30_CMD_READOUT_FOR_PERIODIC_MODE, buff, 6);

    /* 转换温度数据 */
    tmp = ((uint16_t)buff[0]<<8) | buff[1];
    *temperature = -45 + 175*((float)tmp/65535);

    /* 转换湿度数据 */
    tmp = ((uint16_t)buff[3]<<8) | buff[4];
    *humidity = 100 * ((float)tmp/65535);

    return 0;
}



